from flask import Flask, render_template, request, jsonify, redirect, url_for, flash, session
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash
import jwt
import json
from datetime import datetime, timedelta
import os
import re
from vocabulary_estimator import VocabularyEstimator
from batch_processor import BatchProcessor
import statistics
from collections import defaultdict

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-super-secret-key-change-this-in-production'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///vocabulary.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['MAX_CONTENT_LENGTH'] = 10 * 1024 * 1024  # 10MB 文件大小限制

db = SQLAlchemy(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'

# 数据库模型
class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    password_hash = db.Column(db.String(120), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.now)
    cet4_score = db.Column(db.Integer, nullable=True)  # 四级成绩
    cet6_score = db.Column(db.Integer, nullable=True)  # 六级成绩
    test_results = db.relationship('TestResult', backref='user', lazy=True)

class TestResult(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    test_type = db.Column(db.String(20), nullable=False)  # 'interactive', 'corpus', 'batch'
    vocabulary_estimate = db.Column(db.Integer, nullable=False)
    confidence = db.Column(db.Float, nullable=False)
    test_data = db.Column(db.Text, nullable=False)  # JSON格式存储测试数据
    created_at = db.Column(db.DateTime, default=datetime.now)
    cet4_score = db.Column(db.Integer)
    cet6_score = db.Column(db.Integer)

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

# 初始化词汇量估算器
estimator = VocabularyEstimator()
batch_processor = BatchProcessor()

def extract_text_from_file(file_content, filename):
    """从文件内容中提取文本"""
    file_extension = os.path.splitext(filename)[1].lower()
    
    if file_extension == '.txt':
        # 文本文件直接返回内容
        return file_content.decode('utf-8', errors='ignore')
    
    elif file_extension in ['.doc', '.docx']:
        # Word文档的简单文本提取
        try:
            # 简单的文本提取（查找可打印字符）
            text = ''
            for byte in file_content:
                if 32 <= byte <= 126:  # 可打印ASCII字符
                    text += chr(byte)
            
            # 清理文本
            text = re.sub(r'[^\x20-\x7E]', ' ', text)  # 只保留可打印字符
            text = re.sub(r'\s+', ' ', text)  # 合并多个空格
            return text.strip()
        except Exception as e:
            return f"Error extracting text from Word document: {str(e)}"
    
    elif file_extension == '.pdf':
        # PDF文件需要特殊处理
        return "PDF文件需要特殊处理，请将内容复制到文本框中"
    
    else:
        return "不支持的文件格式"

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/health')
def health_check():
    """健康检查端点"""
    try:
        # 检查数据库连接
        db.session.execute('SELECT 1')
        
        # 检查核心模块
        estimator_status = hasattr(estimator, 'estimate_vocabulary_with_level')
        batch_status = hasattr(batch_processor, 'process_batch')
        
        return jsonify({
            'status': 'healthy',
            'timestamp': datetime.now().isoformat(),
            'database': 'connected',
            'modules': {
                'vocabulary_estimator': estimator_status,
                'batch_processor': batch_status
            },
            'version': '1.0.0'
        })
    except Exception as e:
        return jsonify({
            'status': 'unhealthy',
            'timestamp': datetime.now().isoformat(),
            'error': str(e)
        }), 500

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        data = request.get_json()
        username = data.get('username')
        email = data.get('email')
        password = data.get('password')
        
        if User.query.filter_by(username=username).first():
            return jsonify({'success': False, 'message': '用户名已存在'})
        
        if User.query.filter_by(email=email).first():
            return jsonify({'success': False, 'message': '邮箱已存在'})
        
        user = User(
            username=username,
            email=email,
            password_hash=generate_password_hash(password)
        )
        db.session.add(user)
        db.session.commit()
        
        return jsonify({'success': True, 'message': '注册成功'})
    
    return render_template('register.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        data = request.get_json()
        username = data.get('username')
        password = data.get('password')
        
        user = User.query.filter_by(username=username).first()
        if user and check_password_hash(user.password_hash, password):
            login_user(user)
            token = generate_token(user)
            session['token'] = token
            return jsonify({'success': True, 'message': '登录成功', 'token': token})
        
        return jsonify({'success': False, 'message': '用户名或密码错误'})
    
    return render_template('login.html')

@app.route('/logout')
@login_required
def logout():
    logout_user()
    session.pop('token', None)
    return redirect(url_for('index'))

@app.route('/dashboard')
@login_required
def dashboard():
    user_results = TestResult.query.filter_by(user_id=current_user.id).order_by(TestResult.created_at.desc()).all()
    return render_template('dashboard.html', results=user_results)

@app.route('/test')
@login_required
def test():
    return render_template('test.html')

@app.route('/api/estimate_vocabulary', methods=['POST'])
def estimate_vocabulary():
    """估算词汇量 - 使用专门的词汇测试算法"""
    try:
        data = request.get_json()
        test_data = data.get('test_data', [])
        
        if not test_data:
            return jsonify({'success': False, 'message': '测试数据不能为空'})
        
        # 使用专门的词汇测试算法
        vocabulary_size, confidence = estimator.estimate_vocabulary(test_data)
        
        # 获取等级信息
        level_name, level_display, level_color = estimator.get_vocabulary_level(vocabulary_size)
        level_info = estimator.get_level_description(level_name)
        
        # 提取已知和未知单词用于分析
        known_words = [item['word'] for item in test_data if item.get('known', False)]
        unknown_words = [item['word'] for item in test_data if not item.get('known', False)]
        all_words = known_words + unknown_words
        
        # 计算详细分析信息
        if all_words:
            # 词汇复杂度分析
            avg_word_length = statistics.mean([len(word) for word in all_words])
            word_length_variance = statistics.variance([len(word) for word in all_words]) if len(all_words) > 1 else 0
            
            # 词频分析
            frequency_ranks = [estimator.get_word_frequency_rank(word) for word in all_words]
            avg_frequency_rank = statistics.mean(frequency_ranks)
            rare_words_ratio = len([r for r in frequency_ranks if r > 10000]) / len(frequency_ranks)
            
            # 词汇级别分析
            level_counts = defaultdict(int)
            for word in all_words:
                level = estimator.get_word_level(word)
                level_counts[level] += 1
            
            total_words = len(all_words)
            level_ratios = {level: count/total_words for level, count in level_counts.items()}
            
            # 学术词汇识别
            academic_words, weighted_academic_score = estimator.get_academic_words(all_words)
            academic_ratio = len(academic_words) / total_words
            weighted_academic_ratio = weighted_academic_score / total_words
            
            # 计算综合复杂度得分
            complexity_score = estimator.calculate_corpus_complexity(
                avg_word_length, word_length_variance, avg_frequency_rank, 
                rare_words_ratio, level_ratios, weighted_academic_ratio, 
                0, 0  # 句型复杂度设为0，因为词汇测试没有句子
            )
        else:
            # 默认值
            avg_word_length = 0
            avg_frequency_rank = 0
            rare_words_ratio = 0
            academic_ratio = 0
            complexity_score = 0
            level_ratios = {}
            total_words = 0
        
        result = {
            'vocabulary_size': vocabulary_size,
            'confidence': confidence,
            'level': {
                'name': level_name,
                'display': level_display,
                'color': level_color,
                'info': level_info
            },
            'analysis': {
                'total_words': total_words,
                'known_words': len(known_words),
                'unknown_words': len(unknown_words),
                'accuracy': len(known_words) / total_words if total_words > 0 else 0,
                'avg_word_length': round(avg_word_length, 2),
                'avg_frequency_rank': int(avg_frequency_rank),
                'rare_words_ratio': round(rare_words_ratio, 3),
                'academic_ratio': round(academic_ratio, 3),
                'complexity_score': round(complexity_score, 3),
                'level_distribution': level_ratios
            }
        }
        
        # 保存测试记录
        if current_user.is_authenticated:
            test_record = TestResult(
                user_id=current_user.id,
                test_type='interactive',
                vocabulary_estimate=result['vocabulary_size'],
                confidence=result['confidence'],
                test_data=json.dumps(test_data),
                cet4_score=None,
                cet6_score=None,
                created_at=datetime.now()
            )
            db.session.add(test_record)
            db.session.commit()
        
        return jsonify({
            'success': True,
            'vocabulary_size': result['vocabulary_size'],
            'confidence': result['confidence'],
            'level': result['level'],
            'analysis': result['analysis']
        })
    except Exception as e:
        return jsonify({'success': False, 'message': f'估算失败: {str(e)}'})

@app.route('/batch_test')
@login_required
def batch_test():
    return render_template('batch_test.html')

@app.route('/api/batch_estimate', methods=['POST'])
@login_required
def batch_estimate():
    data = request.get_json()
    word_list = data.get('word_list', '')
    validate_only = data.get('validate_only', False)
    
    try:
        if validate_only:
            # 仅验证格式
            is_valid, message = batch_processor.validate_batch_format(word_list)
            return jsonify({'success': is_valid, 'message': message})
        
        # 执行批处理
        results = batch_processor.process_batch(word_list)
        
        # 保存批处理结果
        for result in results:
            test_result = TestResult(
                user_id=current_user.id,
                test_type='batch',
                vocabulary_estimate=result['estimate'],
                confidence=result['confidence'],
                test_data=json.dumps(result['words']),
                created_at=datetime.now()
            )
            db.session.add(test_result)
        db.session.commit()
        
        return jsonify({'success': True, 'results': results})
    except Exception as e:
        return jsonify({'success': False, 'message': f'批处理失败: {str(e)}'})

@app.route('/corpus_test')
@login_required
def corpus_test():
    return render_template('corpus_test.html')

@app.route('/api/estimate_corpus', methods=['POST'])
def estimate_corpus():
    """从语料估算词汇量"""
    try:
        data = request.get_json()
        text = data.get('text', '')
        
        if not text:
            return jsonify({'success': False, 'message': '文本内容不能为空'})
        
        # 使用新的带等级信息的语料估算方法
        result = estimator.estimate_from_corpus_with_level(text)
        
        # 保存测试记录
        if current_user.is_authenticated:
            test_record = TestResult(
                user_id=current_user.id,
                test_type='corpus',
                vocabulary_estimate=result['vocabulary_size'],
                confidence=result['confidence'],
                test_data=json.dumps({'text_length': len(text)}),
                cet4_score=result['level']['score'] if 'score' in result['level'] else None,
                cet6_score=result['level']['score'] if 'score' in result['level'] else None,
                created_at=datetime.now()
            )
            db.session.add(test_record)
            db.session.commit()
        
        return jsonify({
            'success': True,
            'vocabulary_size': result['vocabulary_size'],
            'confidence': result['confidence'],
            'level': result['level']
        })
    except Exception as e:
        return jsonify({'success': False, 'message': f'估算失败: {str(e)}'})

@app.route('/api/upload_file', methods=['POST'])
@login_required
def upload_file():
    """文件上传处理接口"""
    try:
        if 'file' not in request.files:
            return jsonify({'success': False, 'message': '没有选择文件'})
        
        file = request.files['file']
        if file.filename == '':
            return jsonify({'success': False, 'message': '没有选择文件'})
        
        # 检查文件类型
        allowed_extensions = {'.txt', '.doc', '.docx', '.pdf'}
        file_extension = os.path.splitext(file.filename)[1].lower()
        
        if file_extension not in allowed_extensions:
            return jsonify({'success': False, 'message': '不支持的文件格式'})
        
        # 读取文件内容
        file_content = file.read()
        
        # 提取文本
        extracted_text = extract_text_from_file(file_content, file.filename)
        
        return jsonify({
            'success': True,
            'text': extracted_text,
            'filename': file.filename,
            'message': f'文件 "{file.filename}" 处理成功'
        })
        
    except Exception as e:
        return jsonify({'success': False, 'message': f'文件处理失败: {str(e)}'})

@app.route('/api/validate_algorithm', methods=['POST'])
@login_required
def validate_algorithm():
    """算法验证接口"""
    try:
        validation_results = estimator.validate_algorithm()
        return jsonify({'success': True, 'results': validation_results})
    except Exception as e:
        return jsonify({'success': False, 'message': f'验证失败: {str(e)}'})

@app.route('/api/get_test_words', methods=['POST'])
def get_test_words():
    """获取随机测试词汇"""
    try:
        data = request.get_json()
        count = data.get('count', 50)
        user_level = data.get('user_level', None)  # 'beginner', 'intermediate', 'advanced'
        
        # 获取用户的四六级成绩（如果已登录）
        cet4_score = None
        cet6_score = None
        if current_user.is_authenticated:
            cet4_score = current_user.cet4_score
            cet6_score = current_user.cet6_score
        
        # 生成随机测试词汇
        if cet4_score is not None or cet6_score is not None:
            # 优先使用四六级成绩来生成自适应词汇
            test_words = estimator.generate_adaptive_test_words_with_scores(cet4_score, cet6_score, count)
            print(f"根据四六级成绩生成词汇: CET4={cet4_score}, CET6={cet6_score}")
        elif user_level:
            # 使用用户选择的水平
            test_words = estimator.generate_adaptive_test_words(user_level, count)
            print(f"根据用户水平生成词汇: {user_level}")
        else:
            # 使用默认平衡分布
            test_words = estimator.generate_random_test_words(count)
            print("使用默认平衡分布生成词汇")
        
        return jsonify({
            'success': True,
            'words': test_words,
            'count': len(test_words)
        })
    except Exception as e:
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/api/update_scores', methods=['POST'])
@login_required
def update_scores():
    """更新四级和六级成绩"""
    try:
        data = request.get_json()
        cet4_score = data.get('cet4_score')
        cet6_score = data.get('cet6_score')
        
        # 验证成绩范围
        if cet4_score is not None:
            if not (0 <= cet4_score <= 710):
                return jsonify({'success': False, 'message': '四级成绩必须在0-710之间'})
            current_user.cet4_score = cet4_score
        
        if cet6_score is not None:
            if not (0 <= cet6_score <= 710):
                return jsonify({'success': False, 'message': '六级成绩必须在0-710之间'})
            current_user.cet6_score = cet6_score
        
        db.session.commit()
        
        return jsonify({
            'success': True, 
            'message': '成绩更新成功',
            'cet4_score': current_user.cet4_score,
            'cet6_score': current_user.cet6_score
        })
    except Exception as e:
        return jsonify({'success': False, 'message': f'更新失败: {str(e)}'})

@app.route('/api/get_user_scores', methods=['GET'])
@login_required
def get_user_scores():
    """获取用户成绩"""
    return jsonify({
        'success': True,
        'cet4_score': current_user.cet4_score,
        'cet6_score': current_user.cet6_score
    })

def generate_token(user):
    """生成JWT token"""
    payload = {
        'user_id': user.id, 
        'exp': datetime.now() + timedelta(hours=24)
    }
    return jwt.encode(payload, app.config['SECRET_KEY'], algorithm='HS256')

if __name__ == '__main__':
    with app.app_context():
        db.create_all()
    app.run(debug=True, host='0.0.0.0', port=5000) 